home *** CD-ROM | disk | FTP | other *** search
/ MPEG Toolkit / MPEG Toolkit.iso / os2 / mpegenc / src / pframe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  26.1 KB  |  940 lines

  1. /*===========================================================================*
  2.  * pframe.c                                     *
  3.  *                                         *
  4.  *    Procedures concerned with generation of P-frames             *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    GenPFrame                                 *
  8.  *    ResetPFrameStats                             *
  9.  *    ShowPFrameSummary                             *
  10.  *    EstimateSecondsPerPFrame                         *
  11.  *    ComputeHalfPixelData                             *
  12.  *    SetPQScale                                 *
  13.  *    GetPQScale                                 *
  14.  *                                                                           *
  15.  * NOTE:  when motion vectors are passed as arguments, they are passed as    *
  16.  *        twice their value.  In other words, a motion vector of (3,4) will  *
  17.  *        be passed as (6,8).  This allows half-pixel motion vectors to be   *
  18.  *        passed as integers.  This is true throughout the program.          *
  19.  *                                         *
  20.  *===========================================================================*/
  21.  
  22. /*
  23.  * Copyright (c) 1993 The Regents of the University of California.
  24.  * All rights reserved.
  25.  *
  26.  * Permission to use, copy, modify, and distribute this software and its
  27.  * documentation for any purpose, without fee, and without written agreement is
  28.  * hereby granted, provided that the above copyright notice and the following
  29.  * two paragraphs appear in all copies of this software.
  30.  *
  31.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  32.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  33.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  34.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35.  *
  36.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  37.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  38.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  39.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  40.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  41.  */
  42.  
  43. /*  
  44.  *  $Header: /n/picasso/users/keving/encode/src/RCS/pframe.c,v 1.5 1993/07/22 22:23:43 keving Exp keving $
  45.  *  $Log: pframe.c,v $
  46.  * Revision 1.5  1993/07/22  22:23:43  keving
  47.  * nothing
  48.  *
  49.  * Revision 1.4  1993/06/30  20:06:09  keving
  50.  * nothing
  51.  *
  52.  * Revision 1.3  1993/06/03  21:08:08  keving
  53.  * nothing
  54.  *
  55.  * Revision 1.2  1993/03/02  23:03:42  keving
  56.  * nothing
  57.  *
  58.  * Revision 1.1  1993/02/19  19:14:12  keving
  59.  * nothing
  60.  *
  61.  */
  62.  
  63.  
  64. /*==============*
  65.  * HEADER FILES *
  66.  *==============*/
  67.  
  68. /* @@@ Fake up 'times' interface under OS/2, Andy Key */
  69. #ifdef OS2
  70. #include "os2port.h"
  71. #else
  72. #include <sys/times.h>
  73. #endif
  74. #include "all.h"
  75. #include "mtypes.h"
  76. #include "bitio.h"
  77. #include "frames.h"
  78. #ifdef OS2
  79. /* @@@ FAT 8.3 convention */
  80. #include "prototyp.h"
  81. #else
  82. #include "prototypes.h"
  83. #endif
  84. #include "param.h"
  85. #include "mheaders.h"
  86. #include "fsize.h"
  87. #include "postdct.h"
  88. #include "mpeg.h"
  89. #include "parallel.h"
  90.  
  91.  
  92. /*==================*
  93.  * STATIC VARIABLES *
  94.  *==================*/
  95.  
  96. static int32    zeroDiff;
  97. static int numPIBlocks = 0;
  98. static int numPPBlocks = 0;
  99. static int numPSkipped = 0;
  100. static int numPIBits = 0;
  101. static int numPPBits = 0;
  102. static int numFrames = 0;
  103. static int numFrameBits = 0;
  104. static int32 totalTime = 0;
  105. static int qscaleP;
  106. static float    totalSNR = 0.0;
  107. static float    totalPSNR = 0.0;
  108.  
  109.  
  110. /*===============================*
  111.  * INTERNAL PROCEDURE prototypes *
  112.  *===============================*/
  113.  
  114. static boolean    ZeroMotionBetter _ANSI_ARGS_((LumBlock currentBlock,
  115.                           MpegFrame *prev, int by, int bx,
  116.                           int my, int mx));
  117. static boolean    DoIntraCode _ANSI_ARGS_((LumBlock currentBlock,
  118.                      MpegFrame *prev, int by, int bx,
  119.                      int motionY, int motionX));
  120. static boolean    ZeroMotionSufficient _ANSI_ARGS_((LumBlock currentBlock,
  121.                           MpegFrame *prev,
  122.                           int by, int bx));
  123.  
  124. #ifdef BLEAH
  125. static void    ComputeAndPrintPframeMAD _ANSI_ARGS_((LumBlock currentBlock,
  126.                               MpegFrame *prev,
  127.                               int by, int bx,
  128.                               int my, int mx,
  129.                               int numBlock));
  130. #endif
  131.  
  132.  
  133. /*=====================*
  134.  * EXPORTED PROCEDURES *
  135.  *=====================*/
  136.  
  137. /*===========================================================================*
  138.  *
  139.  * GenPFrame
  140.  *
  141.  *    generate a P-frame from previous frame, adding the result to the
  142.  *    given bit bucket
  143.  *
  144.  * RETURNS:    frame appended to bb
  145.  *
  146.  * SIDE EFFECTS:    none
  147.  *
  148.  *===========================================================================*/
  149. void
  150. GenPFrame(bb, current, prev)
  151.     BitBucket *bb;
  152.     MpegFrame *current;
  153.     MpegFrame *prev;
  154. {
  155.     FlatBlock fba[6], fb[6];
  156.     Block    dec[6];
  157.     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
  158.     int x, y;
  159.     int    motionX = 0, motionY = 0;
  160.     int    oldMotionX = 0, oldMotionY = 0;
  161.     int    offsetX, offsetY;
  162.     int    tempX, tempY;
  163.     int    motionXrem, motionXquot;
  164.     int    motionYrem, motionYquot;
  165.     int    pattern;
  166.     int        mbAddrInc = 1;
  167.     boolean    useMotion;
  168.     int numIBlocks = 0;
  169.     int    numPBlocks = 0;
  170.     int    numSkipped = 0;
  171.     int    numIBits = 0;
  172.     int numPBits = 0;
  173.     int totalBits;
  174.     int    totalFrameBits;
  175.     struct tms timeBuffer;
  176.     int32    startTime, endTime;
  177.     int numBlocks = -1;
  178.     int    lastBlockX, lastBlockY;
  179.     int    lastX, lastY;
  180.     int    fy, fx;
  181.     LumBlock currentBlock;
  182.     register int ix, iy;
  183.     int    frameBlocks;
  184.     int slicePos;
  185.     register int index;
  186.     float   snr[3], psnr[3];
  187.  
  188.     numFrames++;
  189.     totalFrameBits = bb->cumulativeBits;
  190.     times(&timeBuffer);
  191.     startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  192.  
  193.     DBG_PRINT(("Generating pframe\n"));
  194.  
  195.     Mhead_GenPictureHeader(bb, P_FRAME, current->id, fCode);
  196.  
  197.     DBG_PRINT(("Slice Header\n"));
  198.     Mhead_GenSliceHeader(bb, 1, qscaleP, NULL, 0);
  199.  
  200.     if ( referenceFrame == DECODED_FRAME ) {
  201.     Frame_AllocDecoded(current, TRUE);
  202.     } else if ( printSNR ) {
  203.     Frame_AllocDecoded(current, FALSE);
  204.     }
  205.  
  206.     /* don't do dct on blocks yet */
  207.     Frame_AllocBlocks(current);
  208.     BlockifyFrame(current);
  209.  
  210.     /* for I-blocks */
  211.     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  212.  
  213.     totalBits = bb->cumulativeBits;
  214.  
  215.     if ( (! pixelFullSearch) && (! prev->halfComputed) ) {
  216.     ComputeHalfPixelData(prev);
  217.     }
  218.  
  219.     lastBlockX = Fsize_x/8;
  220.     lastBlockY = Fsize_y/8;
  221.     lastX = lastBlockX-2;
  222.     lastY = lastBlockY-2;
  223.     frameBlocks = 0;
  224.  
  225.     for (y = 0; y < lastBlockY; y += 2) {
  226.     for (x = 0; x < lastBlockX; x += 2) {
  227.         slicePos = (frameBlocks % blocksPerSlice);
  228.  
  229.         if ( (slicePos == 0) && (frameBlocks != 0) ) {
  230.         Mhead_GenSliceEnder(bb);
  231.         Mhead_GenSliceHeader(bb, 1+(y/2), qscaleP, NULL, 0);
  232.  
  233.         /* reset everything */
  234.         oldMotionX = 0;        oldMotionY = 0;
  235.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  236.  
  237.         mbAddrInc = 1+(x/2);
  238.         }
  239.  
  240.         numBlocks++;
  241.         frameBlocks++;
  242.  
  243.         /* compute currentBlock */
  244.         BLOCK_TO_FRAME_COORD(y, x, fy, fx);
  245.         for ( iy = 0; iy < 16; iy++ ) {
  246.         for ( ix = 0; ix < 16; ix++ ) {
  247.             currentBlock[iy][ix] = (int16)current->orig_y[fy+iy][fx+ix];
  248.         }
  249.         }
  250.  
  251.         /* see if we should use motion vectors, and if so, what those
  252.          * vectors should be
  253.          */
  254.         if ( ZeroMotionSufficient(currentBlock, prev, y, x) ) {
  255.         motionX = 0;
  256.         motionY = 0;
  257.         pattern = 63;
  258.         useMotion = TRUE;
  259.         } else {
  260.         useMotion = PMotionSearch(currentBlock, prev, y, x,
  261.                       &motionY, &motionX);
  262.  
  263.         pattern = 63;
  264.  
  265.         if ( useMotion ) {
  266.             if ( ZeroMotionBetter(currentBlock, prev, y, x, motionY,
  267.                       motionX) ) {
  268.             motionX = 0;
  269.             motionY = 0;
  270.             pattern = 63;
  271.             }
  272.  
  273.             useMotion = (! DoIntraCode(currentBlock, prev, y, x,
  274.                            motionY, motionX));
  275.         }
  276.         }
  277.  
  278.         if ( ! useMotion ) {
  279.         /* output I-block inside a P-frame */
  280.         numIBlocks++;
  281.  
  282.         /* calculate forward dct's */
  283.         mp_fwd_dct_block(current->y_blocks[y][x]);
  284.         mp_fwd_dct_block(current->y_blocks[y][x+1]);
  285.         mp_fwd_dct_block(current->y_blocks[y+1][x]);
  286.         mp_fwd_dct_block(current->y_blocks[y+1][x+1]);
  287.         mp_fwd_dct_block(current->cb_blocks[y >> 1][x >> 1]);
  288.         mp_fwd_dct_block(current->cr_blocks[y >> 1][x >> 1]);
  289.  
  290.         GEN_I_BLOCK(P_FRAME, current, bb, mbAddrInc, qscaleP);
  291.         mbAddrInc = 1;
  292.  
  293.         numIBits += (bb->cumulativeBits-totalBits);
  294.         totalBits = bb->cumulativeBits;
  295.  
  296.         /* reset because intra-coded */
  297.         oldMotionX = 0;        oldMotionY = 0;
  298.  
  299.         if ( decodeRefFrames ) {
  300.             /* need to decode block we just encoded */
  301.             Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleP, TRUE);
  302.             Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleP, TRUE);
  303.             Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleP, TRUE);
  304.             Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleP, TRUE);
  305.             Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleP, TRUE);
  306.             Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleP, TRUE);
  307.  
  308.             /* now, reverse the DCT transform */
  309.             for ( index = 0; index < 6; index++ ) {
  310.             j_rev_dct((int16 *)dec[index]);
  311.             }
  312.  
  313.             /* now, unblockify */
  314.             BlockToData(current->decoded_y, dec[0], y, x);
  315.             BlockToData(current->decoded_y, dec[1], y, x+1);
  316.             BlockToData(current->decoded_y, dec[2], y+1, x);
  317.             BlockToData(current->decoded_y, dec[3], y+1, x+1);
  318.             BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
  319.             BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
  320.         }
  321.         } else {
  322.         /* USE MOTION VECTORS */
  323.         numPBlocks++;
  324.  
  325.         /* reset because non-intra-coded */
  326.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  327.  
  328. #ifdef BLEAH
  329.     ComputeAndPrintPframeMAD(currentBlock, prev, y, x, motionY, motionX, numBlocks);
  330. #endif
  331.  
  332.         ComputeDiffDCTs(current, prev, y, x, motionY, motionX,
  333.                 pattern);
  334.  
  335.         if ( pixelFullSearch ) {    /* should be even */
  336.             motionY /= 2;
  337.             motionX /= 2;
  338.         }
  339.  
  340.         /* transform the motion vector into the appropriate values */
  341.         offsetX = motionX - oldMotionX;
  342.         offsetY = motionY - oldMotionY;
  343.  
  344.         ENCODE_MOTION_VECTOR(offsetX, offsetY, motionXquot,
  345.                      motionYquot, motionXrem, motionYrem,
  346.                      FORW_F);
  347.  
  348. #ifdef BLEAH
  349.     if ( (motionX != 0) || (motionY != 0) ) {
  350.     fprintf(stdout, "FRAME (y, x)  %d, %d (block %d)\n", y, x, numBlocks);
  351.     fprintf(stdout, "motionX = %d, motionY = %d\n", motionX, motionY);
  352.     fprintf(stdout, "    mxq, mxr = %d, %d    myq, myr = %d, %d\n",
  353.         motionXquot, motionXrem, motionYquot, motionYrem);
  354. }
  355. #endif
  356.  
  357.         oldMotionX = motionX;
  358.         oldMotionY = motionY;
  359.  
  360.         if ( pixelFullSearch ) {/* reset for use with PMotionSearch */
  361.             motionY *= 2;
  362.             motionX *= 2;
  363.         }
  364.  
  365.         /* create flat blocks and update pattern if necessary */
  366.     if ( (pattern & 0x20) && 
  367.          (! Mpost_QuantZigBlock(current->y_blocks[y][x], fba[0],
  368.                    qscaleP, FALSE)) ) {
  369.         pattern ^= 0x20;
  370.     }
  371.     if ( (pattern & 0x10) && 
  372.          (! Mpost_QuantZigBlock(current->y_blocks[y][x+1], fba[1],
  373.                    qscaleP, FALSE)) ) {
  374.         pattern ^= 0x10;
  375.     }
  376.     if ( (pattern & 0x8) && 
  377.          (! Mpost_QuantZigBlock(current->y_blocks[y+1][x], fba[2],
  378.                    qscaleP, FALSE)) ) {
  379.         pattern ^= 0x8;
  380.     }
  381.     if ( (pattern & 0x4) && 
  382.          (! Mpost_QuantZigBlock(current->y_blocks[y+1][x+1], fba[3],
  383.                    qscaleP, FALSE)) ) {
  384.         pattern ^= 0x4;
  385.     }
  386.     if ( (pattern & 0x2) && 
  387.          (! Mpost_QuantZigBlock(current->cb_blocks[y >> 1][x >> 1], fba[4],
  388.                    qscaleP, FALSE)) ) {
  389.         pattern ^= 0x2;
  390.     }
  391.     if ( (pattern & 0x1) && 
  392.          (! Mpost_QuantZigBlock(current->cr_blocks[y >> 1][x >> 1], fba[5],
  393.                    qscaleP, FALSE)) ) {
  394.         pattern ^= 0x1;
  395.     }
  396.  
  397.     if ( decodeRefFrames ) {
  398.         if ( pattern & 0x20 ) {
  399.         Mpost_UnQuantZigBlock(fba[0], dec[0], qscaleP, FALSE);
  400.         } else {
  401.         bzero((char *)dec[0], sizeof(Block));
  402.         }
  403.         if ( pattern & 0x10 ) {
  404.         Mpost_UnQuantZigBlock(fba[1], dec[1], qscaleP, FALSE);
  405.         } else {
  406.         bzero((char *)dec[1], sizeof(Block));
  407.         }
  408.         if ( pattern & 0x8 ) {
  409.         Mpost_UnQuantZigBlock(fba[2], dec[2], qscaleP, FALSE);
  410.         } else {
  411.         bzero((char *)dec[2], sizeof(Block));
  412.         }
  413.         if ( pattern & 0x4 ) {
  414.         Mpost_UnQuantZigBlock(fba[3], dec[3], qscaleP, FALSE);
  415.         } else {
  416.         bzero((char *)dec[3], sizeof(Block));
  417.         }
  418.         if ( pattern & 0x2 ) {
  419.         Mpost_UnQuantZigBlock(fba[4], dec[4], qscaleP, FALSE);
  420.         } else {
  421.         bzero((char *)dec[4], sizeof(Block));
  422.         }
  423.         if ( pattern & 0x1 ) {
  424.         Mpost_UnQuantZigBlock(fba[5], dec[5], qscaleP, FALSE);
  425.         } else {
  426.         bzero((char *)dec[5], sizeof(Block));
  427.         }
  428.  
  429.         /* now, reverse the DCT transform */
  430.         for ( index = 0; index < 6; index++ ) {
  431.         if ( GET_ITH_BIT(pattern, 5-index) ) {
  432.             j_rev_dct((int16 *)dec[index]);
  433.         }
  434.         }
  435.  
  436.         /* now add the motion block */
  437.         AddMotionBlock(dec[0], prev->decoded_y, y, x, motionY, motionX);
  438.         AddMotionBlock(dec[1], prev->decoded_y, y, x+1, motionY, motionX);
  439.         AddMotionBlock(dec[2], prev->decoded_y, y+1, x, motionY, motionX);
  440.         AddMotionBlock(dec[3], prev->decoded_y, y+1, x+1, motionY, motionX);
  441.         AddMotionBlock(dec[4], prev->decoded_cb, y>>1, x>>1, motionY/2, motionX/2);
  442.         AddMotionBlock(dec[5], prev->decoded_cr, y>>1, x>>1, motionY/2, motionX/2);
  443.  
  444.         /* now, unblockify */
  445.         BlockToData(current->decoded_y, dec[0], y, x);
  446.         BlockToData(current->decoded_y, dec[1], y, x+1);
  447.         BlockToData(current->decoded_y, dec[2], y+1, x);
  448.         BlockToData(current->decoded_y, dec[3], y+1, x+1);
  449.         BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
  450.         BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
  451.     }
  452.  
  453.         if ( (motionX == 0) && (motionY == 0) ) {
  454.             if ( pattern == 0 ) {
  455.             /* can only skip if:
  456.              *     1)  not the last block in frame
  457.              *     2)  not the last block in slice
  458.              *     3)  not the first block in slice
  459.              */
  460.             if ( ((y < lastY) || (x < lastX)) &&
  461.                  (slicePos+1 != blocksPerSlice) &&
  462.                  (slicePos != 0) ) {
  463.                 mbAddrInc++;    /* skipped macroblock */
  464.                 numSkipped++;
  465.                 numPBlocks--;
  466.             } else {    /* last macroblock */
  467.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  468.               0 /* mb_quant */, 0 /* q_scale */,
  469.               fCode /* forw_f_code */, 1 /* back_f_code */,
  470.               0 /* horiz_forw_r */, 0 /* vert_forw_r */,
  471.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  472.               0 /* motion_forw */, 0 /* m_horiz_forw */,
  473.               0 /* m_vert_forw */, 0 /* motion_back */,
  474.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  475.               1 /* mb_pattern */, 0 /* mb_intra */);
  476.             mbAddrInc = 1;
  477.  
  478.                 Bitio_Write(bb, 0x2, 2); /* first coeff */
  479.                 Bitio_Write(bb, 0x2, 2); /* end of block */
  480.             }
  481.             } else {
  482.             DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  483.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  484.               0 /* mb_quant */, 0 /* q_scale */,
  485.               fCode /* forw_f_code */, 1 /* back_f_code */,
  486.               0 /* horiz_forw_r */, 0 /* vert_forw_r */,
  487.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  488.               0 /* motion_forw */, 0 /* m_horiz_forw */,
  489.               0 /* m_vert_forw */, 0 /* motion_back */,
  490.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  491.               pattern /* mb_pattern */, 0 /* mb_intra */);
  492.             mbAddrInc = 1;
  493.             }
  494.         } else {
  495.         DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  496.         Mhead_GenMBHeader(bb, 2 /* pict_code_type */, mbAddrInc /* addr_incr */,
  497.               0 /* mb_quant */, 0 /* q_scale */,
  498.               fCode /* forw_f_code */, 1 /* back_f_code */,
  499.               motionXrem /* horiz_forw_r */, motionYrem /* vert_forw_r */,
  500.               0 /* horiz_back_r */, 0 /* vert_back_r */,
  501.               1 /* motion_forw */, motionXquot /* m_horiz_forw */,
  502.               motionYquot /* m_vert_forw */, 0 /* motion_back */,
  503.               0 /* m_horiz_back */, 0 /* m_vert_back */,
  504.               pattern /* mb_pattern */, 0 /* mb_intra */);
  505.             mbAddrInc = 1;
  506.         }
  507.  
  508.         /* now output the difference */
  509.         for ( tempX = 0; tempX < 6; tempX++ ) {
  510.             if ( GET_ITH_BIT(pattern, 5-tempX) ) {
  511.             Mpost_RLEHuffPBlock(fba[tempX], bb);
  512.             }
  513.         }
  514.  
  515.         numPBits += (bb->cumulativeBits-totalBits);
  516.         totalBits = bb->cumulativeBits;
  517.         }
  518.     }
  519.     }
  520.  
  521.     if ( printSNR ) {
  522.         ComputeSNR(current->orig_y, current->decoded_y, Fsize_y, Fsize_x,
  523.            &snr[0], &psnr[0]);
  524.         ComputeSNR(current->orig_cb, current->decoded_cb, Fsize_y/2, Fsize_x/2,
  525.            &snr[1], &psnr[1]);
  526.         ComputeSNR(current->orig_cr, current->decoded_cr, Fsize_y/2, Fsize_x/2,
  527.            &snr[2], &psnr[2]);
  528.  
  529.     totalSNR += snr[0];
  530.     totalPSNR += psnr[0];
  531.     }
  532.  
  533.     Mhead_GenSliceEnder(bb);
  534.  
  535.     /* UPDATE STATISTICS */
  536.     times(&timeBuffer);
  537.     endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  538.     totalTime += (endTime-startTime);
  539.  
  540.     if ( (! childProcess) && frameSummary ) {
  541.     fprintf(stdout, "FRAME %d (P):  I BLOCKS:  %d;  P BLOCKS:  %d   SKIPPED:  %d  (%ld seconds)\n",
  542.         current->id, numIBlocks, numPBlocks, numSkipped, (long)(endTime-startTime)/60);
  543.     if ( printSNR ) {
  544.         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
  545.             current->id, snr[0], snr[1], snr[2],
  546.             psnr[0], psnr[1], psnr[2]);
  547.     }
  548.     }
  549.  
  550.     numFrameBits += (bb->cumulativeBits-totalFrameBits);
  551.     numPIBlocks += numIBlocks;
  552.     numPPBlocks += numPBlocks;
  553.     numPSkipped += numSkipped;
  554.     numPIBits += numIBits;
  555.     numPPBits += numPBits;
  556.  
  557.     if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
  558.     if ( remoteIO ) {
  559.         SendDecodedFrame(current);
  560.     } else {
  561.         WriteDecodedFrame(current);
  562.     }
  563.  
  564.     NotifyDecodeServerReady(current->id);
  565.     }
  566. }
  567.  
  568.  
  569. /*===========================================================================*
  570.  *
  571.  * ResetPFrameStats
  572.  *
  573.  *    reset the P-frame statistics
  574.  *
  575.  * RETURNS:    nothing
  576.  *
  577.  * SIDE EFFECTS:    none
  578.  *
  579.  *===========================================================================*/
  580. void
  581. ResetPFrameStats()
  582. {
  583.     numPIBlocks = 0;
  584.     numPPBlocks = 0;
  585.     numPSkipped = 0;
  586.     numPIBits = 0;
  587.     numPPBits = 0;
  588.     numFrames = 0;
  589.     numFrameBits = 0;
  590.     totalTime = 0;
  591. }
  592.  
  593.  
  594. /*===========================================================================*
  595.  *
  596.  * SetPQScale
  597.  *
  598.  *    set the P-frame Q-scale
  599.  *
  600.  * RETURNS:    nothing
  601.  *
  602.  * SIDE EFFECTS:    qscaleP
  603.  *
  604.  *===========================================================================*/
  605. void
  606. SetPQScale(qP)
  607.     int qP;
  608. {
  609.     qscaleP = qP;
  610. }
  611.  
  612.  
  613. /*===========================================================================*
  614.  *
  615.  * GetPQScale
  616.  *
  617.  *    return the P-frame Q-scale
  618.  *
  619.  * RETURNS:    the P-frame Q-scale
  620.  *
  621.  * SIDE EFFECTS:    none
  622.  *
  623.  *===========================================================================*/
  624. int
  625. GetPQScale()
  626. {
  627.     return qscaleP;
  628. }
  629.  
  630.  
  631. /*===========================================================================*
  632.  *
  633.  * ShowPFrameSummary
  634.  *
  635.  *    print a summary of information on encoding P-frames
  636.  *
  637.  * RETURNS:    nothing
  638.  *
  639.  * SIDE EFFECTS:    none
  640.  *
  641.  *===========================================================================*/
  642. void
  643. ShowPFrameSummary(inputFrameBits, totalBits, fpointer)
  644.     int inputFrameBits;
  645.     int32 totalBits;
  646.     FILE *fpointer;
  647. {
  648.     if ( numFrames == 0 ) {
  649.     return;
  650.     }
  651.  
  652.     fprintf(fpointer, "-------------------------\n");
  653.     fprintf(fpointer, "*****P FRAME SUMMARY*****\n");
  654.     fprintf(fpointer, "-------------------------\n");
  655.  
  656.     if ( numPIBlocks != 0 ) {
  657.     fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  658.         numPIBlocks, numPIBits, numPIBits/numPIBlocks);
  659.     } else {
  660.     fprintf(fpointer, "  I Blocks:  %5d\n", 0);
  661.     }
  662.  
  663.     if ( numPPBlocks != 0 ) {
  664.     fprintf(fpointer, "  P Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  665.         numPPBlocks, numPPBits, numPPBits/numPPBlocks);
  666.     } else {
  667.     fprintf(fpointer, "  P Blocks:  %5d\n", 0);
  668.     }
  669.  
  670.     fprintf(fpointer, "  Skipped:   %5d\n", numPSkipped);
  671.  
  672.     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
  673.         numFrames, numFrameBits, numFrameBits/numFrames,
  674.         100.0*(float)numFrameBits/(float)totalBits);
  675.     fprintf(fpointer, "  Compression:  %3d:1\n",
  676.         numFrames*inputFrameBits/numFrameBits);
  677.     if ( printSNR )
  678.     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
  679.         totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
  680.     fprintf(fpointer, "  Seconds:  %9ld     (%9ld spf)     (%9ld bps)\n",
  681.         (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
  682.         (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
  683. }
  684.  
  685.  
  686. /*===========================================================================*
  687.  *
  688.  * EstimateSecondsPerPFrame
  689.  *
  690.  *    compute an estimate of the number of seconds required per P-frame
  691.  *
  692.  * RETURNS:    the estimate, in seconds
  693.  *
  694.  * SIDE EFFECTS:    none
  695.  *
  696.  *===========================================================================*/
  697. float
  698. EstimateSecondsPerPFrame()
  699. {
  700.     if ( numFrames == 0 ) {
  701.     return 10.0;
  702.     } else {
  703.     return (float)totalTime/(60.0*(float)numFrames);
  704.     }
  705. }
  706.  
  707.  
  708. /*===========================================================================*
  709.  *
  710.  * ComputeHalfPixelData
  711.  *
  712.  *    compute all half-pixel data required for half-pixel motion vector
  713.  *    search (luminance only)
  714.  *
  715.  * RETURNS:    frame->halfX, ->halfY, and ->halfBoth modified
  716.  *
  717.  * SIDE EFFECTS:    none
  718.  *
  719.  *===========================================================================*/
  720. void
  721. ComputeHalfPixelData(frame)
  722.     MpegFrame *frame;
  723. {
  724.     register int x, y;
  725.  
  726.     /* we add 1 before dividing by 2 because .5 is supposed to be rounded up
  727.      * (see MPEG-1, page D-31)
  728.      */
  729.  
  730.     if ( frame->halfX == NULL ) {        /* need to allocate memory */
  731.         Frame_AllocHalf(frame);
  732.     }
  733.  
  734.     /* compute halfX */
  735.     for ( y = 0; y < Fsize_y; y++ ) {
  736.     for ( x = 0; x < Fsize_x-1; x++ ) {
  737.         frame->halfX[y][x] = (frame->ref_y[y][x]+
  738.                   frame->ref_y[y][x+1]+1)/2;
  739.     }
  740.     }
  741.  
  742.     /* compute halfY */
  743.     for ( y = 0; y < Fsize_y-1; y++ ) {
  744.     for ( x = 0; x < Fsize_x; x++ ) {
  745.         frame->halfY[y][x] = (frame->ref_y[y][x]+
  746.                   frame->ref_y[y+1][x]+1)/2;
  747.     }
  748.     }
  749.  
  750.     /* compute halfBoth */
  751.     for ( y = 0; y < Fsize_y-1; y++ ) {
  752.     for ( x = 0; x < Fsize_x-1; x++ ) {
  753.         frame->halfBoth[y][x] = (frame->ref_y[y][x]+
  754.                      frame->ref_y[y][x+1]+
  755.                      frame->ref_y[y+1][x]+
  756.                      frame->ref_y[y+1][x+1]+2)/4;
  757.     }
  758.     }
  759.  
  760.     frame->halfComputed = TRUE;
  761. }
  762.  
  763.  
  764. /*=====================*
  765.  * INTERNAL PROCEDURES *
  766.  *=====================*/
  767.  
  768. /*===========================================================================*
  769.  *
  770.  *                  USER-MODIFIABLE
  771.  *
  772.  * ZeroMotionBetter
  773.  *
  774.  *    decide if (0,0) motion is better than the given motion vector
  775.  *
  776.  * RETURNS:    TRUE if (0,0) is better, FALSE if (my,mx) is better
  777.  *
  778.  * SIDE EFFECTS:    none
  779.  *
  780.  * PRECONDITIONS:    The relevant block in 'current' is valid (it has not
  781.  *            been dct'd).  'zeroDiff' has already been computed
  782.  *            as the LumMotionError() with (0,0) motion
  783.  *
  784.  * NOTES:    This procedure follows the algorithm described on
  785.  *        page D-48 of the MPEG-1 specification
  786.  *
  787.  *===========================================================================*/
  788. static boolean
  789. ZeroMotionBetter(currentBlock, prev, by, bx, my, mx)
  790.     LumBlock currentBlock;
  791.     MpegFrame *prev;
  792.     int by;
  793.     int bx;
  794.     int my;
  795.     int mx;
  796. {
  797.     int    bestDiff;
  798.  
  799.     bestDiff = LumMotionError(currentBlock, prev, by, bx, my, mx, 0x7fffffff);
  800.  
  801.     if ( zeroDiff < 256*3 ) {
  802.     if ( 2*bestDiff >= zeroDiff ) {
  803.         return TRUE;
  804.     }
  805.     } else {
  806.     if ( 11*bestDiff >= 10*zeroDiff ) {
  807.         return TRUE;
  808.     }
  809.     }
  810.  
  811.     return FALSE;
  812. }
  813.  
  814.  
  815. /*===========================================================================*
  816.  *
  817.  *                  USER-MODIFIABLE
  818.  *
  819.  * DoIntraCode
  820.  *
  821.  *    decide if intra coding is necessary
  822.  *
  823.  * RETURNS:    TRUE if intra-block coding is better; FALSE if not
  824.  *
  825.  * SIDE EFFECTS:    none
  826.  *
  827.  * PRECONDITIONS:    The relevant block in 'current' is valid (it has not
  828.  *            been dct'd).
  829.  *
  830.  * NOTES:    This procedure follows the algorithm described on
  831.  *        page D-49 of the MPEG-1 specification
  832.  *
  833.  *===========================================================================*/
  834. static boolean
  835. DoIntraCode(currentBlock, prev, by, bx, motionY, motionX)
  836.     LumBlock currentBlock;
  837.     MpegFrame *prev;
  838.     int by;
  839.     int bx;
  840.     int motionY;
  841.     int motionX;
  842. {
  843.     int        x, y;
  844.     int32 sum = 0, vard = 0, varc = 0, dif;
  845.     int32 currPixel, prevPixel;
  846.     LumBlock    motionBlock;
  847.     int        fy, fx;
  848.  
  849.     ComputeMotionLumBlock(prev, by, bx, motionY, motionX, motionBlock);
  850.  
  851.     MOTION_TO_FRAME_COORD(by, bx, 0, 0, fy, fx);
  852.  
  853.     for ( y = 0; y < 16; y++ ) {
  854.     for ( x = 0; x < 16; x++ ) {
  855.         currPixel = currentBlock[y][x];
  856.         prevPixel = motionBlock[y][x];
  857.  
  858.         sum += currPixel;
  859.         varc += currPixel*currPixel;
  860.  
  861.         dif = currPixel - prevPixel;
  862.         vard += dif*dif;
  863.     }
  864.     }
  865.  
  866.     vard /= 256;    /* assumes mean is close to zero */
  867.     varc = varc/256 - (sum/256)*(sum/256);
  868.  
  869.     if ( vard <= 64 ) {
  870.     return FALSE;
  871.     } else if ( vard < varc ) {
  872.     return FALSE;
  873.     } else {
  874.     return TRUE;
  875.     }
  876. }
  877.  
  878.  
  879. /*===========================================================================*
  880.  *
  881.  *                  USER-MODIFIABLE
  882.  *
  883.  * ZeroMotionSufficient
  884.  *
  885.  *    decide if zero motion is sufficient without DCT correction
  886.  *
  887.  * RETURNS:    TRUE no DCT required; FALSE otherwise
  888.  *
  889.  * SIDE EFFECTS:    none
  890.  *
  891.  * PRECONDITIONS:    The relevant block in 'current' is raw YCC data
  892.  *
  893.  *===========================================================================*/
  894. static boolean
  895. ZeroMotionSufficient(currentBlock, prev, by, bx)
  896.     LumBlock currentBlock;
  897.     MpegFrame *prev;
  898.     int by;
  899.     int bx;
  900. {
  901.     LumBlock    motionBlock;
  902.     register int    fy, fx;
  903.     register int    x, y;
  904.  
  905.     fy = by*DCTSIZE;
  906.     fx = bx*DCTSIZE;
  907.     for ( y = 0; y < 16; y++ ) {
  908.     for ( x = 0; x < 16; x++ ) {
  909.         motionBlock[y][x] = prev->ref_y[fy+y][fx+x];
  910.     }
  911.     }
  912.  
  913.     zeroDiff = LumBlockMAD(currentBlock, motionBlock, 0x7fffffff);
  914.  
  915.     return (zeroDiff <= 256);
  916. }
  917.                  
  918.  
  919. #ifdef UNUSED_PROCEDURES
  920. static void
  921. ComputeAndPrintPframeMAD(currentBlock, prev, by, bx, my, mbx, numBlock)
  922.     LumBlock currentBlock;
  923.     MpegFrame *prev;
  924.     int by;
  925.     int bx;
  926.     int my;
  927.     int mx;
  928.     int numBlock;
  929. {
  930.     LumBlock    lumMotionBlock;
  931.     int32   mad;
  932.  
  933.     ComputeMotionLumBlock(prev, by, bx, my, mx, lumMotionBlock);
  934.  
  935.     mad = LumBlockMAD(currentBlock, lumMotionBlock, 0x7fffffff);
  936.  
  937.     fprintf(stdout, "%d %d\n", numBlock, mad);
  938. }
  939. #endif
  940.